# 35. re模块 - 正则匹配模块
# re模块
用于使用正则表达式来匹配字符串的内容
# 匹配
# findall方法
findall:匹配所有能匹配上的字符
返回值类型:列表
使用格式:re.findall("正则表达式","要过滤的字符串") 或 变量 = re.findall("正则表达式","要过滤的字符串")
import re
sre = re.findall("\d+","1213skdjalkl1231nkl1231klnlkjh31")
print(sre)
执行结果:
['1213', '1231', '1231', '31']
如果匹配没有,则返回空列表
# search方法
search:匹配第一个结果,简单按规定的正则匹配,匹配到就马上返回结果,不会在匹配接下来的字符串
返回值类型:正则匹配的对象
使用格式:re.search("正则表达式","要过滤的字符串") 或 变量 = re.search("正则表达式","要过滤的字符串")
import re
sre = re.search("\d+","1213skdjalkl1231nkl1231klnlkjh31")
print(type(sre))
print(sre)
执行结果:
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(0, 4), match='1213'>
如果匹配没有,则返回None
# group方法
使用group方法来查看search方法获取到的取
返回值类型:字符串类型
使用格式:变量.group()
import re
sre = re.search("\d+","1213skdjalkl1231nkl1231klnlkjh31")
print(sre.group())
执行结果:
1213
如果查询search方法获取的取为None,那么会报错
通过if判断,来避免程序报错停止
import re
sre = re.search("\d+","1213skdjalkl1231nkl1231klnlkjh31")
if sre :print(sre.group())
执行结果:
1213
# match方法
match:使用方式跟search方法差不多,区别就是:match会在输入的正则表达的开头加个^,代表就是使用match只是获取第一个结果并这个结果是要在开头就有的,如果没有则没
返回值类型:正则匹配的对象
使用格式:re.match("正则表达式","要过滤的字符串") 或 变量 = re.match("正则表达式","要过滤的字符串")
import re
sre = re.match("\d+","1213skdjalkl1231nkl1231klnlkjh31")
print(type(sre))
print(sre)
执行结果:
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(0, 4), match='1213'>
如果匹配没有,则返回None
这里见证match的特别之处
import re
sre = re.match("\d+","s1213skdjalkl1231nkl1231klnlkjh31")
print(sre)
执行结果:
None
那为什么结果是None,因为match方法会默认跟写好的正则开头加上^ ,这样子我们的正则就相当变成这样:^\d+
# group方法
使用group方法来查看match方法获取到的取
返回值类型:字符串类型
使用格式:变量.group()
import re
sre = re.match("\d+","1213skdjalkl1231nkl1231klnlkjh31")
print(sre.group())
执行结果:
1213
如果查询search方法获取的取为None,那么会报错
通过if判断,来避免程序报错停止
import re
sre = re.match("\d+","1213skdjalkl1231nkl1231klnlkjh31")
if sre :print(sre.group())
执行结果:
1213
# 替换
# sub方法
sub方法,按正则规则匹配出来的值进行替换处理
返回值类型:字符串类型
格式:re.sub("正则规则","要替换的值","要处理的字符串",要替换的次数)
注意:sub替换次数参数默认是替换全部,如果要替换几次可以指定
res = re.sub("\d","S","asjdkl12131klasklf1231sfq12k12kh312h3j1h2k3")
print(type(res))
print(res)
执行结果:
<class 'str'>
asjdklSSSSSklasklfSSSSsfqSSkSSkhSSShSjShSkS
如果正则匹配没有,那么会输出原先的字符串
指定替换次数
import re
res = re.sub("\d","S","asjdkl12131klasklf1231sfq12k12kh312h3j1h2k3",2)
print(res)
执行结果:
asjdklSS131klasklf1231sfq12k12kh312h3j1h2k3
# subn方法
subn方法使用方式跟sub差不多,只是返回值有点不同,返回的有替换后的值还有替换的次数
返回值类型:元组类型
格式:re.subn("正则规则","要替换的值","要处理的字符串",要替换的次数)
注意:subn替换次数参数默认是替换全部,如果要替换几次可以指定
import re
res = re.subn("\d","S","asjdkl12131klasklf1231sfq12k12kh312h3j1h2k3")
print(type(res))
print(res)
执行结果:
<class 'tuple'>
('asjdklSSSSSklasklfSSSSsfqSSkSSkhSSShSjShSkS', 20)
如果正则匹配没有,那么会输出原先的字符串
指定替换次数
import re
res = re.subn("\d","S","asjdkl12131klasklf1231sfq12k12kh312h3j1h2k3",2)
print(res)
执行结果:
('asjdklSS131klasklf1231sfq12k12kh312h3j1h2k3', 2)
# 切割
# split方法
可以通过split按指定的正则规则来切割分隔开来
返回值类型:列表类型
格式:re.split("正则规则","字符串")
import re
res = re.split("\d","江凡22李城18万须21")
print(type(res))
print(res)
执行结果:
<class 'list'>
['江凡', '', '李城', '', '万须', '', '']
# 进阶
# 预编译功能-compile
如果大量使用相同的正则来过滤字符串,那么每一次过滤都要编译一次正则代码,这样会大大的消耗内存空间跟时间
这样子就可以使用预编译功能方法-compile
格式:变量 = re.compile("正则规则")
res = re.compile("^[1-9]\d{16}[0-9x]|^[1-9]\d{14}")
rew = res.findall("123456789012345678")
ree = res.search("876543210987654321")
print(rew)
print(ree.group())
执行结果:
['123456789012345678']
876543210987654321
# 迭代器-finditer
将匹配出来的可以用迭代器来循环输出,输出的值是一个对象,需要加了gtoup方法来取值
一般用于处理大量的字符串数据
格式:re.finditer("正则规则","要匹配的字符串")
import re
res = re.finditer("\d","sahd12h367897894564h12h31jg657683hj1g3h21313g5575671hj3g25454361hj2g1h312354jg3hj1g3hj")
for i in res:
print(i)
执行结果:
<_sre.SRE_Match object; span=(4, 5), match='1'>
<_sre.SRE_Match object; span=(5, 6), match='2'>
<_sre.SRE_Match object; span=(7, 8), match='3'>
<_sre.SRE_Match object; span=(8, 9), match='6'>
.......
# group方法
使用group方法来查看finditer迭代后的对象的结果
import re
res = re.finditer("\d","sahd12h367897894564h12h31jg657683hj1g3h21313g5575671hj3g25454361hj2g1h312354jg3hj1g3hj")
for i in res:
print(i.group())
执行结果:
1
2
3
6
......
# 当re模块遇上正则分组
# 当findall方法遇上分组
到findall方法中的正则有分组 () 时,那么findall方法就会以分组优先
分组优先:只显示分组中的内容
res = re.findall("www.baidu.cn|www.linux91.cn","www.linux91.cn")
ree = re.findall("www\.(baidu|linux91)\.cn","www.linux91.cn")
print(res)
print(ree)
执行结果:
['www.linux91.cn']
['linux91']
分组优先是可以取消的,取消分组优先需要要在正则中的分组里加上 ?: 这二个符号(?😃
res = re.findall("www.baidu.cn|www.linux91.cn","www.linux91.cn")
ree = re.findall("www\.(?:baidu|linux91)\.cn","www.linux91.cn")
print(res)
print(ree)
执行结果:
['www.linux91.cn']
['www.linux91.cn']
就算使用compile对正则进行预编译也一样,需要加上?:
res = re.compile("www\.(baidu|linux91)\.cn")
rew = re.compile("www\.(?:baidu|linux91)\.cn")
res = res.findall("www.linux91.cn")
rew = rew.findall("www.linux91.cn")
print(res)
print(rew)
执行结果:
['linux91']
['www.linux91.cn']
# 当search方法遇上分组
先不说,先看一段代码
rew = re.search('\d+(.\d+)(.\d+)(.\d+)?','1.2.3.4-2*(60+(-40.35/5)-(-4*3))')
print(rew.group())
print(rew.group(0))
print(rew.group(1))
print(rew.group(2))
print(rew.group(3))
执行结果:
1.2.3.4
1.2.3.4
.2
.3
.4
有没有发现一些规律,简单来说,当search方法遇到分组的作用,不是像findall方法一样,自动触发,而是需要手动触发,触方式:在于group方法
- group()或group(0):默认显示全部分组内容
- group(1):显示第一个分组的内容
- group(2):显示第二个分组的内容
- group(3):显示第三个分组的内容
- group(4):显示第四个分组的内容
- ......等等
# 当split方法遇上分组
就直接简单说,当split中的正则有分组,那么就会显示分组中切割消失的值
rew = re.split("\d+","江凡22李城18万须21")
res = re.split("(\d+)","江凡22李城18万须21")
print(rew)
print(res)
执行结果:
['江凡', '李城', '万须', '']
['江凡', '22', '李城', '18', '万须', '21', '']
# 分组练习题
# 去除匹配的值中不要值
可以利用findall方法中的分组优先来去除匹配后的值中不想要的值
字符串:1-2*(60+(-40.35/5)-(-4*3))
匹配字符串中的所有整数跟小数,并去除小数
import re
rew = re.findall("\d+(?:\.\d+)|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
rew.remove("")
print(rew)
执行结果:
['1', '2', '60', '5', '4', '3']
# 分别获取指定的指推荐使用-search方法
字符串:"<a>abc</a>"
匹配字符串中的<>中的a
匹配字符串中的二个<>中间的值:abc
# 使用findall方法
rew = re.findall("<(\w+)>","<a>abc</a>")
print(rew)
ree = re.findall(">(\w+)<","<a>abc</a>")
print(ree)
执行结果:
['a']
['abc']
# 使用search方法
rew = re.search("<(\w+)>(\w+)</(\w+)>","<a>abc</a>")
print(rew.group(1))
print(rew.group(2))
执行结果:
a
abc
# 分组命名
分组命令,可以把一个分组进行命名,在正则中另一处使用
比如:<h1>ksjakldf</h1>,匹配h1中的所有数据,那要怎么确实<h1>的结尾是<\h1>,难道正则要这样写"<h1>(\w+)<\h1>",这样子不行,因为这样子正则规则就限制在只能匹配<h1>的内容,所以要使用分组命名来保证
分组命名分为二种:分组命名,分组索引
# 分组命名
findall方法
## 没值
rew = re.findall('<(?P<mos>\w+)>(\w+)</(?P=mos)>','<a>wahaha</b>')
print(rew)
## 正确
rew = re.findall('<(?P<mos>\w+)>(\w+)</(?P=mos)>','<a>wahaha</a>')
print(rew)
执行结果:
[('a', 'wahaha')]
为什么会没值,因为如果正则中有命名,并有使用命令,Python会将这二个位置的值进行对比,如果相同则执行下去,如果不相同则取消执行
search方法
## 正常操作
rew = re.search('<(?P<mos>\w+)>(\w+)</(?P=mos)>','<a>wahaha</a>')
print(rew.group())
执行结果:
<a>wahaha</a>
## 指定分组命名显值
rew = re.search('<(?P<mos>\w+)>(\w+)</(?P=mos)>','<a>wahaha</a>')
print(rew.group("mos"))
执行结果:
a
# 索引分组
索引分组按索引来调用分组,从1开始算
rew = re.search('<(\w+)>(\w+)</\\1>','<a>wahaha</a>')
print(rew.group())
执行结果:
<a>wahaha</a>
# re模块中所有方法的flags选项
flags选项这个选项在re中的所有方法都有这个选项
一共有六个用法,博主分为二部分,常用跟不常用
用法
re.findall("正则","字符串",re.S)
## 所有方法使用flags选项,类似以上findall方法的用法
# 常用
常用用法分为三种
- re.I:忽略大小写,完整的写法:IGNORECASE
- re.M:忽略换行符,多行模式,改变^跟$的行为,完整的写法:MULTILINE
- re.S:让 . 字符可以匹配任意字符,包括换行符,完整的写法:DOTALL
# 不常用
不常用用法也分为三种
- re.L:做本地化识别的匹配,表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境,不推荐使用,完整的写法:LOCALE
- re.U:使用\w \W \s \S \d \D使用取决于unicode定义的字符属性。在python3中默认使用该flag,完整的写法:UNICODE
- re.X:冗长模式,该模式下pattern字符串可以是多行的,忽略空白字符,并可以添加注释,完整的写法:VERBOSE